﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Ocmf.Types;
using Action=Ocmf.Types.Action;

namespace Ocmf.Forms
{
    public partial class MainForm : Form
    {
        private Timer chamberExplorerRefreshTimer = new Timer();

        public MainForm()
        {
            InitializeComponent();
            //ensure that the client tries to connect on startup regardless of last use
            LocalSettings.DbOnline = true;
            LocalSettings.SaveToRegistry();
        }

        private void InitializeSessionExplorer()
        {
            chamberExplorerRefreshTimer.Tick += refreshChambers;
            chamberExplorerRefreshTimer.Interval = LocalSettings.ChamberExplorerRefreshInterval;
        }

        void refreshChambers(object sender, EventArgs e)
        {
            if (LocalSettings.DbOnline) DatabaseProvider.RefreshChambers();

            //clear all chambers from the component
            chambersDataGridView.Rows.Clear();
            
            foreach (var chamber in DatabaseProvider.Chambers.Values)
                chambersDataGridView.Rows.Add(new object[] { chamber.HostName, chamberStatusImageList.Images[Enum.GetName(typeof(ChamberState), chamber.LastKnownStatus)], chamber.LastSeenAlive, chamber.IpAddress });
        }

        private void InitializeExperimentExplorer()
        {
            DatabaseProvider.SynchronizeExperimentFolder();
            //ensure user has the most up-to-date templates if a new experiment is designed
            if (LocalSettings.DbOnline) DatabaseProvider.RefreshScreenTemplates();
            
            //initialize properties
            treeViewExperiment.Text = "Unsaved Experiment";
            updateWindowText();

            //load all images into imagelist
            if (Directory.Exists(LocalSettings.ApplicationImageFolder))
            {
                //PNG Files
                var imageFileNames = Directory.GetFiles(LocalSettings.ApplicationImageFolder, "*.png");
                foreach (var imageFileName in imageFileNames)
                    treeViewExperiment.ImageList.Images.Add(Path.GetFileName(imageFileName), Image.FromFile(imageFileName));

                //JPG Files
                imageFileNames = Directory.GetFiles(LocalSettings.ApplicationImageFolder, "*.jpg");
                foreach (var imageFileName in imageFileNames)
                    treeViewExperiment.ImageList.Images.Add(Path.GetFileName(imageFileName), Image.FromFile(imageFileName));
                //BMP Files
                imageFileNames = Directory.GetFiles(LocalSettings.ApplicationImageFolder, "*.bmp");
                foreach (var imageFileName in imageFileNames)
                    treeViewExperiment.ImageList.Images.Add(Path.GetFileName(imageFileName), Image.FromFile(imageFileName));
                //GIF Files
                imageFileNames = Directory.GetFiles(LocalSettings.ApplicationImageFolder, "*.gif");
                foreach (var imageFileName in imageFileNames)
                    treeViewExperiment.ImageList.Images.Add(Path.GetFileName(imageFileName), Image.FromFile(imageFileName));
            }
        }

        private void InitializeChamberExplorer()
        {

        }

        private void toolStripButtonAddExperiment_Click(object sender, EventArgs e)
        {
            var openFileDialog = new OpenFileDialog();
            openFileDialog.Title = "Please select a Screen Template...";
            openFileDialog.Filter = "Screen Template File (*" + LocalSettings.FileExtensionScreenTemplate + ")|*" + LocalSettings.FileExtensionScreenTemplate;
            openFileDialog.InitialDirectory = LocalSettings.ApplicationScreenTemplateFolder;
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                treeViewExperiment.ScreenTemplate =new ScreenTemplate();
                treeViewExperiment.ScreenTemplate.Open(openFileDialog.FileName);
                toolStripButtonAddTrial_Click(this, EventArgs.Empty);
            }
        }

        private void toolStripButtonAddTrial_Click(object sender, EventArgs e)
        {
            //create new trial
            var trialNode = new Trial();
            //add the number of cards associated with the experiment
            trialNode.Nodes.Add(new Folder() {Text = "Pre-Trial Actions"});
            var stimuliFolder = new Folder() {Text = "Stimuli"};

            for (var i = 0; i < treeViewExperiment.ScreenTemplate.Controls.Count; i++)
                stimuliFolder.Nodes.Add(new Card());
            
            //add the trial to the treeview
            trialNode.Nodes.Add(stimuliFolder);

            trialNode.Nodes.Add(new Folder() { Text = "Post-Trial Actions" });

            treeViewExperiment.Nodes.Add(trialNode);
            //

            //TODO: encapsulate into method
            foreach (Trial trial in treeViewExperiment.Nodes)
                trial.Alias = trial.Alias;
            trialNode.ExpandAll();
        }

        private void addFoodToolStripButton_Click(object sender, EventArgs e)
        {
            if (treeViewExperiment.SelectedNode == null || (treeViewExperiment.SelectedNode.GetType() != typeof(Folder) && treeViewExperiment.SelectedNode.GetType() != typeof(Card)) || treeViewExperiment.SelectedNode.Text == "Stimuli") return;
            treeViewExperiment.SelectedNode.Nodes.Add(new Food());
            treeViewExperiment.SelectedNode.ExpandAll();
        }

        private void addGoToTrialToolStripButton_Click(object sender, EventArgs e)
        {
            if (treeViewExperiment.SelectedNode == null || (treeViewExperiment.SelectedNode.GetType() != typeof(Folder) && treeViewExperiment.SelectedNode.GetType() != typeof(Card)) || treeViewExperiment.SelectedNode.Text == "Stimuli") return;
            treeViewExperiment.SelectedNode.Nodes.Add(new GoTo());
            treeViewExperiment.SelectedNode.ExpandAll();
        }

        private void addHouseLightToolStripButton_Click(object sender, EventArgs e)
        {
            if (treeViewExperiment.SelectedNode == null || (treeViewExperiment.SelectedNode.GetType() != typeof(Folder) && treeViewExperiment.SelectedNode.GetType() != typeof(Card)) || treeViewExperiment.SelectedNode.Text == "Stimuli") return;
            treeViewExperiment.SelectedNode.Nodes.Add(new HouseLight());
            treeViewExperiment.SelectedNode.ExpandAll();
        }

        private void addPrlToolStripButton_Click(object sender, EventArgs e)
        {
            if (treeViewExperiment.SelectedNode == null || (treeViewExperiment.SelectedNode.GetType() != typeof(Folder) && treeViewExperiment.SelectedNode.GetType() != typeof(Card)) || treeViewExperiment.SelectedNode.Text == "Stimuli") return;
            treeViewExperiment.SelectedNode.Nodes.Add(new Prl());
            treeViewExperiment.SelectedNode.ExpandAll();
        }

        private void addBuzzerToolStripButton_Click(object sender, EventArgs e)
        {
            if (treeViewExperiment.SelectedNode == null || (treeViewExperiment.SelectedNode.GetType() != typeof(Folder) && treeViewExperiment.SelectedNode.GetType() != typeof(Card)) || treeViewExperiment.SelectedNode.Text == "Stimuli") return;
            treeViewExperiment.SelectedNode.Nodes.Add(new Buzzer());
            treeViewExperiment.SelectedNode.ExpandAll();
        }

        private void addStopToolStripButton_Click(object sender, EventArgs e)
        {
            if (treeViewExperiment.SelectedNode == null || (treeViewExperiment.SelectedNode.GetType() != typeof(Folder) && treeViewExperiment.SelectedNode.GetType() != typeof(Card)) || treeViewExperiment.SelectedNode.Text == "Stimuli") return;
            treeViewExperiment.SelectedNode.Nodes.Add(new Stop());
            treeViewExperiment.SelectedNode.ExpandAll();
        }

        private void toolStripButtonPromoteAction_Click(object sender, EventArgs e)
        {
            if (treeViewExperiment.SelectedNode.PrevNode != null &&
                treeViewExperiment.SelectedNode.Index > 0)
            {
                var node = treeViewExperiment.SelectedNode.PrevNode;
                node.Remove();
                treeViewExperiment.SelectedNode.Parent.Nodes.Insert(treeViewExperiment.SelectedNode.Index + 1, node);
            }
        }

        private void toolStripButtonDemoteAction_Click(object sender, EventArgs e)
        {
            if (treeViewExperiment.SelectedNode.NextNode != null &&
                treeViewExperiment.SelectedNode.Index < treeViewExperiment.SelectedNode.Parent.Nodes.Count - 1)
            {
                var node = treeViewExperiment.SelectedNode.NextNode;
                node.Remove();
                treeViewExperiment.SelectedNode.Parent.Nodes.Insert(treeViewExperiment.SelectedNode.Index, node);
            }
        }

        private void treeViewExperiment_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (((Action)e.Node).Editor != null)
                ((Action)e.Node).Editor.ShowDialog();
        }

        private void deleteActionToolStripButton_Click(object sender, EventArgs e)
        {
            if(treeViewExperiment.SelectedNode == null)return;
            var nodeType = treeViewExperiment.SelectedNode.GetType();
            if (nodeType == typeof(Card)) return;
            if (nodeType == typeof(Trial) && treeViewExperiment.Nodes.Count == 1) return;
            
            treeViewExperiment.SelectedNode.Remove();
            
            if(nodeType == typeof(Trial))
                foreach (Trial trial in treeViewExperiment.Nodes)
                    trial.Alias = trial.Alias;
        }

        private void editToolStripButton_Click(object sender, EventArgs e)
        {
            if (treeViewExperiment.SelectedNode == null) return;
            if (((Action)treeViewExperiment.SelectedNode).Editor != null)
                ((Action)treeViewExperiment.SelectedNode).Editor.ShowDialog();
        }

        private void delayToolStripButton_Click(object sender, EventArgs e)
        {
            if (treeViewExperiment.SelectedNode == null || (treeViewExperiment.SelectedNode.GetType() != typeof(Folder) && treeViewExperiment.SelectedNode.GetType() != typeof(Card)) || treeViewExperiment.SelectedNode.Text == "Stimuli") return;
            treeViewExperiment.SelectedNode.Nodes.Add(new Delay());
            treeViewExperiment.SelectedNode.ExpandAll();
        }

        private void autogenerateToolStripButton1_Click(object sender, EventArgs e)
        {
            //recurse to root of the selected  node - get trial object used for setting up referencing
            var trialRoot = treeViewExperiment.SelectedNode;
            while(trialRoot.Parent != null)
                trialRoot = trialRoot.Parent;


            var currentPreTrialActions = trialRoot.Nodes[0];
            var currentStimuli = trialRoot.Nodes[1];
            var currentPostTrialActions = trialRoot.Nodes[2];

            var cardList = new List<Card>();

            foreach (Card card in currentStimuli.Nodes)
                cardList.Add(card);

            var permutationList = new List<Trial>();
            recursePermutations(new List<Card>(), cardList, permutationList,(Folder)currentPreTrialActions, (Folder)currentPostTrialActions);

            treeViewExperiment.Nodes.Clear();

            foreach (Trial permutation in permutationList)
                treeViewExperiment.Nodes.Add(permutation);

            treeViewExperiment.ExpandAll();

            foreach (Trial trial in treeViewExperiment.Nodes)
                trial.Alias = trial.Alias;
        }

        private void recursePermutations(List<Card> currentPermutation, List<Card> remainingCards, List<Trial> trialPermutations, Folder preTrialActions, Folder postTrialActions)
        {
            if (remainingCards.Count == 0)
            {
                var newTrial = new Trial();
                var newPreTrialActions = new Folder {Text = "Pre-Trial Actions"};
                foreach (Action action in preTrialActions.Nodes)
                    newPreTrialActions.Nodes.Add((Action)action.Clone());
                newTrial.Nodes.Add(newPreTrialActions);

                var stimuli = new Folder() { Text = "Stimuli" };
                foreach (Card card in currentPermutation)
                    stimuli.Nodes.Add(card);
                newTrial.Nodes.Add(stimuli);

                var newPostTrialActions = new Folder {Text = "Post-Trial Actions"};
                foreach (Action action in postTrialActions.Nodes)
                    newPostTrialActions.Nodes.Add((Action) action.Clone());
                newTrial.Nodes.Add(newPostTrialActions);

                trialPermutations.Add(newTrial);
            }

            for (var i = 0; i < remainingCards.Count; i++)
            {
                var newPermutation = new List<Card>();
                foreach (Card card in currentPermutation)
                    newPermutation.Add((Card)card.Clone());
                newPermutation.Add((Card)remainingCards[i].Clone());
                var remainingCards2 = new List<Card>();
                foreach (Card card in remainingCards)
                    remainingCards2.Add((Card)card.Clone());
                remainingCards2.RemoveAt(i);
                recursePermutations(newPermutation, remainingCards2, trialPermutations, preTrialActions, postTrialActions);
            }
        }

        private void counterToolStripButton_Click(object sender, EventArgs e)
        {
            if (treeViewExperiment.SelectedNode == null || (treeViewExperiment.SelectedNode.GetType() != typeof(Folder) && treeViewExperiment.SelectedNode.GetType() != typeof(Card)) || treeViewExperiment.SelectedNode.Text == "Stimuli") return;
            var newCounter = new Counter();
            treeViewExperiment.SelectedNode.Nodes.Add(newCounter);
            if(!treeViewExperiment.Counters.Contains(newCounter.Alias))
                treeViewExperiment.Counters.Add(newCounter.Alias);
            treeViewExperiment.SelectedNode.ExpandAll();
        }

        private void openToolStripButton_Click(object sender, EventArgs e)
        {
            if(!treeViewExperiment.CheckSaveState() && MessageBox.Show("The current experiment is not saved. Would you like to do so?",
                            "Current Experiment Not Saved", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
            {
                var saveFileDialog = new SaveFileDialog();
                saveFileDialog.FileName = Path.GetFileName(treeViewExperiment.FileName);
                saveFileDialog.Filter = "ExperimentFiles (*.experiment)|*.experiment";
                saveFileDialog.InitialDirectory = Path.GetDirectoryName(treeViewExperiment.FileName);
                if (saveFileDialog.ShowDialog() == DialogResult.OK)
                    treeViewExperiment.Save(saveFileDialog.FileName);
            }
            
            var openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "Experiment Files (*.experiment)|*.experiment";
            openFileDialog.InitialDirectory = LocalSettings.ApplicationExperimentFolder;
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                treeViewExperiment.Open(openFileDialog.FileName);
                updateWindowText();
            }
        }

        private void saveToolStripButton_Click(object sender, EventArgs e)
        {
            if (treeViewExperiment.FileName == null)
                saveAsStripButton_Click(this, EventArgs.Empty);
            else
                treeViewExperiment.Save();
        }

        private void updateWindowText()
        {
            Text = treeViewExperiment.Text + " - OCMF Client";
        }

        private void saveAsStripButton_Click(object sender, EventArgs e)
        {
            var saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "ExperimentFiles (*.experiment)|*.experiment";
            saveFileDialog.InitialDirectory = LocalSettings.ApplicationExperimentFolder;
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                treeViewExperiment.Text = Path.GetFileNameWithoutExtension(saveFileDialog.FileName);
                treeViewExperiment.Save(saveFileDialog.FileName);
                updateWindowText();
            }
        }

        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            //reset 
            chamberExplorerRefreshTimer.Enabled = false;
            
            switch(tabControl1.SelectedTab.Name)
            {
                case "experimentExplorerTabPage":
                    break;
                case"chamberExplorerTabPage":
                    chamberExplorerRefreshTimer.Enabled = true;
                    refreshChambers(this, EventArgs.Empty);
                    break;
                case "sessionExplorerTabPage":
                    break;
            }
        }

        private void chambersDataGridView_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            chambersDataGridView.Rows[e.RowIndex].Selected = true;
        }

        private void addChamberToolStripButton_Click(object sender, EventArgs e)
        {
            if(new EditChamberForm().ShowDialog() == DialogResult.OK)
                if (LocalSettings.DbOnline) refreshChambers(this, EventArgs.Empty);
        }

        private void editChamberToolStripButton_Click(object sender, EventArgs e)
        {
            if(new EditChamberForm(DatabaseProvider.Chambers[chambersDataGridView.SelectedRows[0].Cells["hostNameColumn"].Value.ToString()]).ShowDialog() == DialogResult.OK)
                if (LocalSettings.DbOnline) refreshChambers(this, EventArgs.Empty);
        }

        private void assignExperimentsToolStripButton_Click(object sender, EventArgs e)
        {
            //stop refreshing chambers
            chamberExplorerRefreshTimer.Enabled = false;

            if (new AssignExperimentForm().ShowDialog() == DialogResult.OK)
                if (LocalSettings.DbOnline) refreshChambers(this, EventArgs.Empty);

            //start refreshing chambers
            chamberExplorerRefreshTimer.Enabled = true;
        }

        private void viewCounterToolStripButton_Click(object sender, EventArgs e)
        {
            if(new ViewCountersForm().ShowDialog() == DialogResult.OK)
                return;
        }

        private void viewSessionLogToolStripButton4_Click(object sender, EventArgs e)
        {
            if(new ViewSessionLogForm().ShowDialog() == DialogResult.OK)
                return;
        }

        private void addScreenTemplateToolStripButton_Click(object sender, EventArgs e)
        {
            if(new EditScreenTemplateForm(new ScreenTemplate()).ShowDialog() == DialogResult.OK)
                return;
        }

        private void MainForm_Shown(object sender, EventArgs e)
        {
            InitializeChamberExplorer();
            InitializeExperimentExplorer();
            InitializeSessionExplorer();
        }
    }
}
